package com.cango.student.io.nio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

public class NioServer extends Thread {
    @Override
    public void run() {
        // 创建selector和channel
        // Selector检测到注册在Selector上的多个Channel中，是否有Channel处于就绪状态，进而实现了单线程对多Channel的高效管理
        try (Selector selector = Selector.open();
             ServerSocketChannel serverSocket = ServerSocketChannel.open()) {

            serverSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 8888));
            // 明确配置非阻塞模式。
            // 注意，为什么我们要明确配置非阻塞模式呢？因为阻塞模式下，注册操作时不允许的，会抛出异常。
            serverSocket.configureBlocking(false);
            // 注册到selector，并说明关注的是新的连接请求
            serverSocket.register(selector, SelectionKey.OP_ACCEPT);

            while (true) {
                // 阻塞等待就绪的Channel
                // Selector阻塞在select操作,当有Channel发生接入请求，就会被唤醒。
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iter = selectionKeys.iterator();
                while (iter.hasNext()) {
                    SelectionKey key = iter.next();
                    // 生产系统中一般会额外进行就绪装袋检查
                    sayHelloWorld((ServerSocketChannel) key.channel());
                    iter.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void sayHelloWorld(ServerSocketChannel Server) throws IOException {
        try (SocketChannel client = Server.accept()) {
            client.write(Charset.defaultCharset().encode("Hello World"));
        }
    }

    public static void main(String[] args) throws IOException {
        NioServer server = new NioServer();
        server.start();

        try (SocketChannel socketChannel = SocketChannel.open()) {
            socketChannel.connect(new InetSocketAddress(InetAddress.getLocalHost(), 8888));
            ByteBuffer buf = ByteBuffer.allocate(1024);
            socketChannel.read(buf);
            buf.flip();
            System.out.println(new String(buf.array(), 0, buf.limit()));
            buf.clear();

        }
        // 利用socket模拟了一个简单客户端，只进行连接，读取，打印
        try (Socket client = new Socket(InetAddress.getLocalHost(), 8888)) {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
            bufferedReader.lines().forEach(s -> System.out.println(s));
        }


        // 读取文件
        RandomAccessFile tFile = new RandomAccessFile("d:\\temp.log", "rw");
        FileChannel channel = tFile.getChannel();
        String newData = "New String to write to file..." + System.currentTimeMillis();
        ByteBuffer buf = ByteBuffer.allocate(48);
        buf.clear();
        buf.put(newData.getBytes());
        buf.flip();
        while(buf.hasRemaining()) {
            channel.write(buf);
        }

        System.exit(1);
    }


}
